<?php

/**
 * Ответ приложения. Может работыть в 2-х режимах: прямой вывод (write) и вывод
 * по шаблону (assign). По умолчанию используется вывод по шаблону, но после
 * первого вывзова write ответ переключается в прямой режим.
 *
 */
abstract class Kernel_Response_Abstract 
{

    /**
     * Флаг, определяющий, что был вызван вывод без шаблона.
     *
     * @var boolean
     */
    private $_written = false;

    /**
     * Устанавливает статус ответа.
     *
     * @param   integer $code
     * @param   string  $text
     * @return  Kernel_Response_Abstract
     */
    public function status($code, $text) 
    {
        $this->_header($_SERVER['SERVER_PROTOCOL'] . ' ' . $code . ' ' . $text);
        return $this;
    }

    /**
     * Отправляет заголовок ответа — хоть и не во всех режимах запуска оно имеет
     * смысл, пока пускай будет здесь.
     *
     * @param   string  $param
     * @param   string  $value
     * @return  Kernel_Response_Abstract
     */
    public function header($param, $value = null) 
    {
        foreach (is_array($param) ? $param : array($param => $value) as $param => $value) {
            $this->_header($param . ': ' . $value);
        }
        return $this;
    }

    /**
     * Выводит в ответ ошибку, описанную указанным исключением.
     *
     * @param   Kernel_Filter_Exception $e
     * @return  Kernel_Response_Abstract
     */
    public function error($e) 
    {
        $this->status($e->getCode(), $e->getStatusText())->header($e->getHeaders());
        return $this;
    }

    /**
     * Пишет содержимое в ответ.
     *
     * @param   string  $contents
     * @return  Kernel_Response_Abstract
     */
    public function write($contents) 
    {
        $this->_written = true;
        echo $contents;
        return $this;
    }

    /**
     * Пишет содержимое в ответ и переводит строку.
     *
     * @param   string  $contents
     * @return  Kernel_Response_Abstract
     */
    public function writeln($contents) 
    {
        return $this->write($contents . "\n");
    }

    /**
     * Пишет данные в ответ.
     *
     * @param   string  $contents
     * @return  Kernel_Response_Abstract
     */
    public function readfile($path) 
    {
        $this->_written = true;
        readfile($path);
        return $this;
    }

    /**
     * Устанавливает значения переменных.
     *
     * @param   mixed   $name
     * @param   mixed   $value
     * @return  Kernel_Response_Abstract
     */
    public function assign($name, $value = null) 
    {
        trigger_error('Assigning variables is not implemented', E_USER_ERROR);
        return $this;
    }

    /**
     * Отображает сообщение с указанными параметрами.
     *
     * @param   boolean $status
     * @param   mixed   $contents
     */
    public function message($status, $contents) 
    {
        $this->_message(new Kernel_Response_Message($status, $contents));
    }

    /**
     * Устанавливает уровень безопасности соединения.
     *
     * @param   boolean $on
     * @return  Kernel_Response_Abstract
     */
    public function secure($on) 
    {
        $request = Application::getRequest();
        if (!@constant('DISABLE_SSL') && $on ^ $request->secure()) {
            $this->header('Location', Application::getRequest()->url($on));
        }
        return $this;
    }

    /**
     * Закрывает ответ.
     *
     */
    public function close() 
    {
        if (!$this->_written) {
            echo $this->_template();
        }
    }

    /**
     * Отображает указанное сообщение.
     *
     * @param   Kernel_Response_Message $message
     */
    abstract protected function _message(Kernel_Response_Message $message);

    /**
     * Возвращает содержимое ответа, сгенерированное по шаблону.
     *
     * @return  string
     */
    protected function _template() 
    {
        trigger_error('Template-based output is not implemented', E_USER_ERROR);
    }

    /**
     * Отправляет заголовок ответа.
     *
     * @param   string  $contents
     */
    protected function _header($contents) 
    {
        header($contents);
    }
    
}
